ReactNative 开发Android App 您所在的位置:网站首页 react android开发 ReactNative 开发Android App

ReactNative 开发Android App

2023-05-18 03:25| 来源: 网络整理| 查看: 265

Android开发平台

谷歌在2007年发布Android 是一个开源的基于 Linux 的移动设备操作系统

支持的设备: phone…

语言: 开发语言是java , 后来因为甲骨文准备对android java收费, 又开始向Kotlin转移

IDE: 开发工具以前是eclipse+sdk, 后来谷歌退出了独立的IDE, Android Studio

打包: 使用签名打包生成.apk文件, 可作为app, 安装在android系统.

 

可用的平台框架

现在开发app主要有四种可选方案

首先是原生, 性能最好, 可是针对不同平台业务代码需要重复开发,

并且每次发版都需要经过应用市场审核

所以为了解决这个问题,  衍生出Cordove+ionic+web的方案,

cordova 是Apache的开源框架, 由PhoneGap演化而来, 

提供的是跨平台运行在各种设备的app壳

Ionic 为Web页面提供UI界面和交互.

然而web版本性能方面有些欠缺.

所以Facebook推出ReactNative采用virtual DOM与native UI控件进行绑定,

因此很好待解决了性能问题.

Flutter使用dart 替换掉JS和V8, 性能据说有有更好的提升.

  Android 架构

 > Linux内核层

    主要包含硬件相关的驱动, 电源管理, 以及内核本身的文件管理, 线程调度, 权限管理, 内存管理等.

> 硬件抽象层

    通过抽象封装硬件“驱动”的接口来进一步降低Android系统与硬件的耦合度;

> 运行库:

    运行时:  核心库, Dalvik 虚拟机(使各java应用拥有独立的进程)

    C++库:  Sqlite, webkit, media, audio, ssl,  openGL, freetype

> JAVA的应用框架: 

    Activity, Windows, View,  notification, package, Telephony, location, resource.

> APP应用

    短信, 浏览器, 拨号, 计算器, …. 

  从Js 层到Java层

前面说明了android系统从底层到app的整体架构,

接下来说明一下react-native 实现的android app是怎么交互的.

画这个图的人把上下颠倒了一下.

> Java层:

  该层主要提供了Android的UI渲染器UIManager(将JavaScript映射成Android Widget)

 > Android Widget 控件

  Fresco图片加载,  okhttp 提供http请求,

  对于ios, 或者windows, 这一层都是native层的类似模块.

> JSEngine: 

  提供js运行环境

> JSBridage:

  负责上下层的通信.

> JavaScript层:

   运行的是react native 的js代码, 包含时间分发, js组件 等

Android Studio开发工具

谷歌提供了统一的夸平台的IDE Android Studio来开发安卓应用, 包含

1. 代码编辑 . 2. 布局预览和编辑 3. 性能分析 4. 模拟器 5. 编译 / 调试 6. 查看和操作 android 设备上的文件  

React Native开发过程中, 这个IDE使用主要是跟模拟器相关的,

 

Environment环境配置

环境上, 需要安装react native命令行工具, python2, JDK和android studio.

添加环境变量, 给android studio安装插件和包.

其中包含sdk, 平台工具, intel硬件加速管理, 模拟器,

27版的api, 从右图可以看到27对应的是android8.1, 之所以不使用最新的28, 是因为目前还不够稳定.

x86的系统, 用于模拟器启动android.

安装好react-native命令行工具,

就可以创建出工程了.

工程里包含android的工程, ios的工程,

依赖的模块, 和app.js, index.js.

进入工程目录, 就可以跑起来打包安装了.

Emulator模拟器

安装或调试之前需要先配一个模拟器

或者将一个android设备配置mtp权限通过usb链接电脑.

ADB(Android Debug Bridge)调试器 path添加:  AppData\Local\Android\Sdk\platform-tools 查看设备: adb devices 远程: adb shell 安装: adb install xxx.apk 卸载: adb uninstall xxx.apk 下载: adb pull 上传: adb push 日志: adb logcat

 Android 的一个通用命令行工具,

帮助PC与模拟器实例或连接的 Android 设备进行通信

首先添加环境变量path添加androidsdk的工具路径

然后就可以通过命令行控制了

Adb会在5037端口运行起来一个负责电脑与设备通信的服务.

AndroidManifest.xml 应用初始化清单

在 Android 系统启动应用组件之前,  

系统通过读取应用的清单, 得知以下信息:

1. 报名, 版本名, 版本号, 默认安装位置

2. 硬件功能: 如相机, 蓝牙, GPS等.

3. 用户权限:  流量, 联系人, 相册, 读写存储等.

4. 需要链接的API库.

5. 启动状态, 比如横屏, 竖屏, 感应, 键盘等.

这里面还有很多节点和属性, 这里就不一一例举了.

link链接

链接的意思是在android 和 ios 工程中引入对某个native库的导入和依赖.

如果手动修改需要找到好几个文件一一添加.

使用命令则可以自动完成这个步骤.

这样做的目的是, 减少不必要库的加载, 从而缩小打包大小.

react-native link xxx android/app/build.gradle android/app/src/main/java/com/AppName/MainApplication.java android/settings.gradle ios/AppName.xcodeproj/project.pbxproj Touchable可触摸组件 TouchableHighlight TouchableNativeFeedback TouchableOpacity TouchableWithoutFeedback onLayout?: (event: LayoutChangeEvent) => void;onLongPress?: (event: GestureResponderEvent) => void; onPress?: (event: GestureResponderEvent) => void;onPressIn?: (event: GestureResponderEvent) => void;onPressOut?: (event: GestureResponderEvent) => void; pressRetentionOffset?: Insets; delayLongPress?: number; delayPressIn?: number; delayPressOut?: number;

除了button控件, 大部分控件无法响应触摸行为.

所以需要依赖Touchable系列控件的包裹.

• 背景会在用户手指按下时变暗 • 在用户按下时形成墨水涟漪 • 会在用户手指按下时降低按钮的透明度 • 不显示任何视觉反馈   Scroll滚动 ScrollView FlatList SectionList onContentSizeChange?: (w: number, h: number) => void; onScroll?: (event: NativeSyntheticEvent) => void; onScrollBeginDrag?: (event: NativeSyntheticEvent) => void; onScrollEndDrag?: (event: NativeSyntheticEvent) => void; onMomentumScrollEnd?: (event: NativeSyntheticEvent) => void; onMomentumScrollBegin?: (event: NativeSyntheticEvent) => void;

滑动操作主要是针对可滚动的控件

ScrollView是基本的

FlatList针对长列表做了内存优化, 仅针对可现实范围内的部分加载到内存

SectionList也有同样的优化, 不过SectionList有分组的功能, 每个组都有独立的header和多行内容.

  http 请求

http 请求, 可以使用fetch接口, 或者XMLHttpRequest

左边是fetch, 右边是XMLHttpRequest,

还可以使用第三方库.

fetch("https://mywebsite.com/endpoint/", { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify({ firstParam: "yourValue", secondParam: "yourOtherValue" }) }) .then(response => response.json()) .then(responseJson => { return responseJson.movies; }) .catch(error => { console.error(error); }); var request = new XMLHttpRequest(); request.onreadystatechange = e => { if (request.readyState !== 4) { return; } if (request.status === 200) { console.log("success", request.responseText); } else { console.warn("error"); } }; request.open("GET", "https://mywebsite.com/endpoint/"); request.send(); File文件访问 \android\app\src\main\AndroidManifest.xml import * as RNFS from "react-native-fs"; export let FileOpt = { writeDataStr: (dataStr: string | void, pathName: string) => { if (dataStr) { RNFS.writeFile( `${RNFS.DocumentDirectoryPath}/${pathName}`, dataStr, 'utf8' ).catch((err)=>{…}); } }, readDataStr: (pathName: string): Promise => { return RNFS.readFile( `${RNFS.DocumentDirectoryPath}/${pathName}`, 'utf8' ); } }

非常奇怪的是RN官方未提供对文件读写的接口.

所以不得不使用第三方提供的库.

这是我封装的文件读写操作接口.

这里需要说明的是, 写单例不能使用class, 因为会导致打包的apk闪退.

所以这里使用的是普通object的写法.

另外, android会限制app的权限, 所以需要在前面提到的AndroidManifest.xml中申明读写权限.

Database数据库

但是关系型数据库, 都是第三方提供的.

WatermelonDB

react-native-sqlite-storage

官方提供的数据库比较简陋, 只有key-value

watermelonDB react-native-sqlite-storage import { AsyncStorage } from "react-native“; setCacheStr: async (keyName: string, valueStr: string | void | null) => { if (keyName && valueStr) { AsyncStorage.setItem(keyName, valueStr) .catch((err)=>{ NativeSdk.log("[StorageOpt: setCacheStr] failed:", err); }); } }, getCacheStr: (keyName: string): Promise => { return AsyncStorage.getItem(keyName); }, Navigation导航

官方提供的navigator

包含tab页导航, 以及跨页面的跳转.

首先是, 定义名字和导航页面的映射.

然后在根页面层的props中可以获取到navigator对象,

使用navigator对象就可以做跳转操作了.

去到一个页面, 然后返回到前一个页面.

也经过多次跳转, 之后回到最初的页面.

const TabNavigator = createBottomTabNavigator({ Collection: { screen: PhotosPage, path: '/TabsCollection', swipeEnabled: true, navigationOptions: { tabBarLabel: '照片', tabBarIcon: ({ tintColor, focused }:any) => ( ), tabBarOptions: tabBarOptions } } }) const tabPages = createAppContainer(TabNavigator); const AppNavigator = createStackNavigator({ Home: tabPages, Photo: BigPhotoPage, Setting: SettingsPage, About: AboutPage }, { initialRouteName: 'Home', headerMode: 'none', }); let PageRouterMain = createAppContainer(AppNavigator); navigation.push("Photo", { name: 'BigPhotoPage', photoParams: photoParams, photoList: photoList }) navigation.goBack() Photos手机照片

获取相片就需要区分平台了,

这里获取相册访问权限, 需要调用PermissionAndroid

获取相机访问权限, 也是类似.

获取到权限之后, 调用CameraRoll.getPhotos才不会发生异常.

在主线程外解码图片

图片解码有可能会需要超过一帧的时间。在 web 上这是页面掉帧的一大因素,

因为解码是在主线程中完成的。然而在 React Native 中,

图片解码则是在另一线程中完成的。不需要改动代码去额外处理。

if (this.getPlatform() === "android") { let granted = null; if (access === "read-storage") { granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.READ_EXTERNAL_STORAGE, {'title': '手机存储', 'message': '访问您的手机存储'} ); } else if (access === "camera") { granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.CAMERA, {'title': '手机摄像头', 'message': '访问您的手机摄像头'} ); } if (granted === PermissionsAndroid.RESULTS.GRANTED) { NativeSdk.log(`requestPermision ${access} granted`); } else { NativeSdk.log(`requestPermision ${access} timeout or denied`); } } } CameraRoll.getPhotos({ first: getNum, assetType: 'Photos', after: cursor }).then((Photos)=>{ resolve(Photos); }).catch(error => { reject(error); }); 需要小心哪些坑? Promise代码调试时, 大半代码, 无法下断点.安装版console.log无输出, 需要额外写文件.启动失败, 也许只是需要删除所有打包缓存文件(每个link过的), 重新运行.几乎一半的非官方库没有同时兼容ios, android.CameraRoll获取的照片地址不是实际地址, 没有后缀, 名字还经常会变.设备的USB经常需要重复多连几次.包含某些库第三方库之后可能导致打包apk失败.日志分散在好几个窗口, 发生错误时不得不一个个检查.

 

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有